﻿Public Class ColorHelper

    Shared colors(16) As Color

    Shared Sub New()
        colors(0) = Color.FromArgb(0, 0, 0)
        colors(1) = Color.FromArgb(0, 0, 128)
        colors(2) = Color.FromArgb(0, 128, 0)
        colors(3) = Color.FromArgb(0, 128, 128)
        colors(4) = Color.FromArgb(128, 0, 0)
        colors(5) = Color.FromArgb(128, 0, 128)
        colors(6) = Color.FromArgb(128, 128, 0)
        colors(7) = Color.FromArgb(192, 192, 192)
        colors(8) = Color.FromArgb(192, 192, 192)
        colors(9) = Color.FromArgb(0, 0, 255)
        colors(10) = Color.FromArgb(0, 255, 0)
        colors(11) = Color.FromArgb(0, 255, 255)
        colors(12) = Color.FromArgb(255, 0, 0)
        colors(13) = Color.FromArgb(255, 0, 255)
        colors(14) = Color.FromArgb(255, 255, 0)
        colors(15) = Color.FromArgb(255, 255, 255)
    End Sub

    Public Shared Sub SetColorChannel(colorName As String, channel As String, value As Byte)
        Dim index As Integer
        Select Case colorName
            Case "BLACK"
                index = 0
            Case "BLUE"
                index = 1
            Case "GREEN"
                index = 2
            Case "CYAN"
                index = 3
            Case "RED"
                index = 4
            Case "MAGENTA"
                index = 5
            Case "BROWN"
                index = 6
            Case "LGRAY"
                index = 7
            Case "DGRAY"
                index = 8
            Case "LBLUE"
                index = 9
            Case "LGREEN"
                index = 10
            Case "LCYAN"
                index = 11
            Case "LRED"
                index = 12
            Case "LMAGENTA"
                index = 13
            Case "YELLOW"
                index = 14
            Case "WHITE"
                index = 15
        End Select

        Dim oldcolor As Color = colors(index)
        Select Case channel
            Case "R"
                colors(index) = Color.FromArgb(value, oldcolor.G, oldcolor.B)
            Case "G"
                colors(index) = Color.FromArgb(oldcolor.R, value, oldcolor.G)
            Case "B"
                colors(index) = Color.FromArgb(oldcolor.R, oldcolor.G, value)
        End Select
    End Sub

    <Obsolete()>
    Public Shared Function GetRawColor(colorNumber As Integer) As Color
        Return colors(colorNumber)
    End Function

    <Obsolete()>
    Private Shared Function GetColorFromTriplet(token As Token, obj As RawObject, colorIndex As Integer, useBright As Boolean) As Color
        If token.Arguments.Count >= 3 Then
            Dim fColor As Integer = 0
            Integer.TryParse(token.Arguments(colorIndex), fColor)
            If useBright AndAlso token.Arguments(2) = "1" Then
                fColor += 8
            End If
            If fColor > 15 Then
                Return Color.Transparent
            Else
                Return colors(fColor)
            End If
        Else
            Return Color.Black
        End If
    End Function

    <Obsolete()>
    Public Shared Function GetBackColorFromTriplet(token As Token, obj As RawObject) As Color
        Return GetColorFromTriplet(token, obj, 1, False)
    End Function

    <Obsolete()>
    Public Shared Function GetForeColorFromTriplet(token As Token, obj As RawObject) As Color
        Return GetColorFromTriplet(token, obj, 0, True)
    End Function

    Public Shared Function Colorize(image As Bitmap, foregroundColor As Color, BackgroundColor As Color) As Bitmap
        Dim temp As New Bitmap(image)
        Dim gr As Graphics = Graphics.FromImage(temp)
        gr.Clear(BackgroundColor)

        ColorHelper.Colorize(image, foregroundColor)
        gr.DrawImage(image, 0, 0)
        gr.Dispose()
        image.Dispose()

        Return temp
    End Function

    Public Shared Sub Colorize(image As Bitmap, color As Color)
        ' Lock the bitmap's bits.  
        Dim rect As New Rectangle(0, 0, image.Width, image.Height)
        Dim bmpData As System.Drawing.Imaging.BitmapData = image.LockBits(rect, _
            Drawing.Imaging.ImageLockMode.ReadWrite, image.PixelFormat)

        ' Get the address of the first line.
        Dim ptr As IntPtr = bmpData.Scan0

        ' Declare an array to hold the bytes of the bitmap.
        ' This code is specific to a bitmap with 24 bits per pixels.
        Dim bytes As Integer = Math.Abs(bmpData.Stride) * image.Height
        Dim rgbValues(bytes - 1) As Byte

        ' Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)

        For pixelIndex As Integer = 0 To rgbValues.Length - 1 Step 4
            Dim rScale As Double = rgbValues(pixelIndex + 2) / 255
            Dim gScale As Double = rgbValues(pixelIndex + 1) / 255
            Dim bScale As Double = rgbValues(pixelIndex + 0) / 255
            'Dim scale As Double = ((CInt(rgbValues(pixelIndex)) + CInt(rgbValues(pixelIndex + 1)) + CInt(rgbValues(pixelIndex + 2))) / 3) / 255
            Dim newRed As Byte = CByte(color.R * rScale)
            Dim newGreen As Byte = CByte(color.G * gScale)
            Dim newBlue As Byte = CByte(color.B * bScale)
            rgbValues(pixelIndex + 2) = newRed
            rgbValues(pixelIndex + 1) = newGreen
            rgbValues(pixelIndex) = newBlue
        Next

        ' Copy the RGB values back to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes)

        ' Unlock the bits.
        image.UnlockBits(bmpData)
    End Sub


    ''' <summary>
    ''' Returns a list of all the unique color values within an image
    ''' </summary>
    ''' <param name="image"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetPallet(image As Bitmap) As List(Of Color)
        Dim uniqueColors As New HashSet(Of Color)

        For y As Integer = 0 To image.Height - 1
            For x As Integer = 0 To image.Width - 1
                Dim c As Color = image.GetPixel(x, y)
                If Not uniqueColors.Contains(c) Then
                    uniqueColors.Add(c)
                End If
            Next
        Next

        Dim ret As New List(Of Color)(uniqueColors)
        ret.Sort(New HueComparer)

        Return ret
    End Function

    Private Class HueComparer
        Implements IComparer(Of Color)

        Public Function Compare(x As System.Drawing.Color, y As System.Drawing.Color) As Integer Implements System.Collections.Generic.IComparer(Of System.Drawing.Color).Compare
            Dim xh As Integer = CInt(x.GetHue)
            Dim yh As Integer = CInt(y.GetHue)

            Dim xb As Integer = CInt(x.GetBrightness * 100)
            Dim yb As Integer = CInt(y.GetBrightness * 100)

            If xh <> yh Then
                Return xh.CompareTo(yh)
            Else
                Return xb.CompareTo(yb)
            End If
        End Function
    End Class

    Public Class ZOrderComparer
        Implements IComparer(Of Color)

        Public Function Compare(x As System.Drawing.Color, y As System.Drawing.Color) As Integer Implements System.Collections.Generic.IComparer(Of System.Drawing.Color).Compare
            Return ZValue(x).CompareTo(ZValue(y))
        End Function

        Private Function ZValue(c As Color) As Long
            Return Split(c.R) + (Split(c.G) << 1) + (Split(c.B) << 2)
        End Function

        Private Function Split(value As Long) As Long
            value = (value Or (value << 12)) And &H1400377
            value = (value Or (value << 8)) And &H14170017
            value = (value Or (value << 4)) And &H303030303
            value = (value Or (value << 2)) And &H1111111111
            Return value
        End Function
    End Class
End Class
